import 'dart:math';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../common/coordinate.dart';

class Paper extends StatefulWidget {
  const Paper({super.key});

  @override
  State<Paper> createState() => _PaperState();
}

class _PaperState extends State<Paper> {
  ui.Image? _image;

  @override
  void initState() {
    super.initState();
    _loadImage();
  }

  void _loadImage() async {
    _image = await loadImageFromAssets('assets/images/ic_head.png');
    setState(() {});
  }

  Future<ui.Image>? loadImageFromAssets(String path) async {
    ByteData data = await rootBundle.load(path);
    return decodeImageFromList(data.buffer.asUint8List());
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: CustomPaint(
        painter: PaperPainter(_image),
      ),
    );
  }
}

class PaperPainter extends CustomPainter {
  final ui.Image? image;

  PaperPainter(this.image);

  static const double step = 15;
  final CoordinateByPath coordinate = CoordinateByPath(step: step);

  final colors = const [
    Color(0xFFF60C0C),
    Color(0xFFF3B913),
    Color(0xFFE7F716),
    Color(0xFF3DF30B),
    Color(0xFF0DF6EF),
    Color(0xFF0829FB),
    Color(0xFFB709F4),
  ];

  final pos = const [1.0 / 7, 2.0 / 7, 3.0 / 7, 4.0 / 7, 5.0 / 7, 6.0 / 7, 1.0];

  @override
  void paint(Canvas canvas, Size size) {
    coordinate.paint(canvas, size);
    // 原点坐标移动到屏幕中心
    canvas.translate(size.width / 2, size.height / 2);

    //drawShaderLinear(canvas);
    //drawShaderRadial(canvas);
    //drawShaderSweep(canvas);
    //drawShaderImage(canvas);
    //drawColorFilter(canvas, size);
    //drawMaskFilter(canvas, size);
    //drawImageFilter(canvas, size);
    drawFilterQuality(canvas, size);
  }

  /// 渐变着色器 - 线性渐变
  // 线性渐变的构造有六个参数，其中起点、终点是 Offset 对象，确定渐变的范围。colors 是颜色数组。这三参是必选的。
  // colorStops 是每个颜色所处的分率，tileMode 是渐变模式，matrix4 是变换矩阵，后三参不是必须的。 下面先来绘制一条彩带，认识一下着色器的使用：
  void drawShaderLinear(Canvas canvas) {
    Paint paint = Paint();
    paint
      ..style = PaintingStyle.stroke
      ..color = Colors.blue
      ..strokeJoin = StrokeJoin.miter
      ..strokeWidth = 50;
    paint.shader =
        ui.Gradient.linear(Offset(0, 0), Offset(100, 0), colors, pos);
    canvas.drawLine(Offset(0, 0), Offset(200, 0), paint);

    // 默认情况下，如果绘制内容超过渐变范围，使用TileMode.clamp使用最后的颜色，继续绘制。
    // 比如上面是 200 的线，渐变范围只到长只有 100。之后都是紫色。
    // 除此之外还有两种模式：径向模式(下图左) TileMode.mirror、重复模式(下图右)TileMode.repeated
    paint.shader = ui.Gradient.linear(
        Offset(0, 0), Offset(100, 0), colors, pos, TileMode.repeated);
    canvas.drawLine(Offset(0, 60), Offset(200, 60), paint);

    // 另外通过 matrix4 可以对画笔填充进行变化。如下，依次是旋转、移动、倾斜
    paint.shader = ui.Gradient.linear(Offset(0, 0), Offset(100, 0), colors, pos,
        TileMode.mirror, Matrix4.rotationZ(pi / 6).storage);
    canvas.drawLine(Offset(0, 120), Offset(200, 120), paint);
    paint.shader = ui.Gradient.linear(Offset(0, 0), Offset(100, 0), colors, pos,
        TileMode.mirror, Matrix4.translationValues(20, 0, 0).storage);
    canvas.drawLine(Offset(0, -60), Offset(200, -60), paint);
    paint.shader = ui.Gradient.linear(Offset(0, 0), Offset(100, 0), colors, pos,
        TileMode.mirror, Matrix4.skewX(-pi / 6).storage);
    canvas.drawLine(Offset(0, -120), Offset(200, -120), paint);
  }

  /// 渐变着色器 - 径向渐变
  // 渐变着色器构造器中传入 8 个参数，必须的参数是 Offset 类型的中心点 center, double 类型的半径 radius,颜色数组 colors,
  // 另外五个参数，前三个和水平渐变一致，另外两个参数用于控制焦点。
  void drawShaderRadial(Canvas canvas) {
    Paint paint = Paint();
    paint
      ..style = PaintingStyle.fill
      ..color = Colors.blue;
    paint.shader = ui.Gradient.radial(Offset(0, 0), 25, colors, pos);
    canvas.drawCircle(Offset(0, 0), 50, paint);

    canvas.translate(120, 0);
    paint.shader =
        ui.Gradient.radial(Offset(0, 0), 25, colors, pos, TileMode.repeated);
    canvas.drawCircle(Offset(0, 0), 50, paint);

    canvas.translate(120, 0);
    paint.shader =
        ui.Gradient.radial(Offset(0, 0), 25, colors, pos, TileMode.mirror);
    canvas.drawCircle(Offset(0, 0), 50, paint);

    canvas.translate(-360, 0);
    paint.shader = ui.Gradient.radial(Offset(0, 0), 25, colors, pos,
        TileMode.mirror, null, Offset(10, 10), 1);
    canvas.drawCircle(Offset(0, 0), 50, paint);
  }

  /// 渐变着色器 - 扫描渐变
  // 渐变着色器构造器中传入 7 个参数，必须的参数是 Offset 类型的中心点 center, 颜色数组 colors。
  // 另外五个参数，colorStops、tileMode、matrix4和前面的一致，另外两个参数用于控制扫描的起止角度。
  void drawShaderSweep(Canvas canvas) {
    Paint paint = Paint();
    paint
      ..style = PaintingStyle.fill
      ..color = Colors.blue;
    paint.shader = ui.Gradient.sweep(
        Offset(0, 0), colors, pos, TileMode.clamp, pi / 2, pi);
    canvas.drawCircle(Offset(0, 0), 50, paint);

    canvas.translate(120, 0);
    paint.shader = ui.Gradient.sweep(
        Offset(0, 0), colors, pos, TileMode.repeated, pi / 2, pi);
    canvas.drawCircle(Offset(0, 0), 50, paint);

    canvas.translate(120, 0);
    paint.shader = ui.Gradient.sweep(
        Offset(0, 0), colors, pos, TileMode.mirror, pi / 2, pi);
    canvas.drawCircle(Offset(0, 0), 50, paint);
  }

  /// 图片着色器 ImageShader
  // 图片着色器相比于渐变来说更强大。它能让画笔自带图片进行绘制，和 PS 中的笔刷有些相像。
  // 构造方法中需要传入ui.Image对象、水平、竖直排列模式及变换矩阵 Float64List。
  void drawShaderImage(Canvas canvas) {
    Paint paint = Paint()
      ..shader = ImageShader(
          image!,
          TileMode.repeated,
          TileMode.repeated,
          Float64List.fromList(
              [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]));

    canvas.drawCircle(Offset(100, 100), 50, paint);

    canvas.translate(0, -120);
    canvas.drawCircle(
        Offset(100, 100),
        50,
        paint
          ..strokeWidth = 10
          ..style = PaintingStyle.stroke);

    canvas.translate(-120, 0);
    canvas.drawLine(
        Offset(100, 50),
        Offset(100, 150),
        paint
          ..strokeWidth = 30
          ..style = PaintingStyle.stroke);
  }

  /// 滤色器 colorFilter
  // ColorFilter对象可以使用变换矩阵或颜色叠合模式对绘制的对象进行滤色处理。
  // const ColorFilter.mode(Color color, BlendMode blendMode) #颜色模式
  // const ColorFilter.matrix(List<double> matrix) #颜色矩阵变换
  void drawColorFilter(Canvas canvas, Size size) {
    canvas.translate(-size.width / 2 + step, -120 - step);
    Paint paint = Paint();

    // 根据混合模式创建滤色器
    //这个效果和 Image 组件的混合模式属性是一致的，通过指定一个颜色和混合模式将绘制内容和颜色进行合成，如下是进行的五个测试
    paint.colorFilter = const ColorFilter.linearToSrgbGamma();
    _drawImage(canvas, paint);

    paint.colorFilter = ColorFilter.mode(Colors.yellow, BlendMode.modulate);
    _drawImage(canvas, paint);

    paint.colorFilter = ColorFilter.mode(Colors.yellow, BlendMode.difference);
    _drawImage(canvas, paint);

    paint.colorFilter = ColorFilter.mode(Colors.blue, BlendMode.plus);
    _drawImage(canvas, paint);

    paint.colorFilter = ColorFilter.mode(Colors.blue, BlendMode.lighten);
    _drawImage(canvas, paint);

    canvas.translate(-(120 + step) * 5, 120 + step);
    // 根据颜色变换矩阵创建滤色器
    // ColorFilter.matrix通过一个5*4的颜色矩阵控制色彩变换。
    // M 代表我们传入的矩阵， C 代表图片某一像素的颜色构成的1*5 矩阵， M 和 C 相乘后，会得到一个 1*4 的矩阵，也就是变换后颜色的值。当所有像素点进行变换后，图片就发生变化了。
    paint.colorFilter = const ColorFilter.matrix(
      <double>[-1, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
    );
    _drawImage(canvas, paint);

    ColorFilter sepia = const ColorFilter.matrix(
      <double>[
        0.393,
        0.769,
        0.189,
        0,
        0,
        0.349,
        0.686,
        0.168,
        0,
        0,
        0.272,
        0.534,
        0.131,
        0,
        0,
        0,
        0,
        0,
        1,
        0
      ],
    );
    _drawImage(canvas, paint..colorFilter = sepia);

    const ColorFilter greyscale = ColorFilter.matrix(<double>[
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0.2126,
      0.7152,
      0.0722,
      0,
      0,
      0,
      0,
      0,
      1,
      0,
    ]);
    _drawImage(canvas, paint..colorFilter = greyscale);

    const n = 90.0;
    const ColorFilter light = ColorFilter.matrix(
        <double>[1, 0, 0, 0, n, 0, 1, 0, 0, n, 0, 0, 1, 0, n, 0, 0, 0, 1, 0]);
    _drawImage(canvas, paint..colorFilter = light);

    const n2 = -126.0;
    const ColorFilter darken = ColorFilter.matrix(<double>[
      1,
      0,
      0,
      0,
      n2,
      0,
      1,
      0,
      0,
      n2,
      0,
      0,
      1,
      0,
      n2,
      0,
      0,
      0,
      1,
      0
    ]);
    _drawImage(canvas, paint..colorFilter = darken);
  }

  /// 遮罩滤镜maskFilter
  // 使图片进行模糊，可以指定模糊的类型, 只有一个MaskFilter.blur构造
  // 类型一共有四种，具体表现效果见下图：
  // const MaskFilter.blur(
  //     this._style, //类型
  //     this._sigma, //高斯模糊的偏差
  //   )
  void drawMaskFilter(Canvas canvas, Size size) {
    canvas.translate(-size.width / 2 + step, -120 - step);
    Paint paint = Paint();

    paint.maskFilter = const MaskFilter.blur(BlurStyle.inner, 20);
    _drawImage(canvas, paint);

    paint.maskFilter = const MaskFilter.blur(BlurStyle.outer, 3);
    _drawImage(canvas, paint);

    paint.maskFilter = const MaskFilter.blur(BlurStyle.solid, 3);
    _drawImage(canvas, paint);

    paint.maskFilter = const MaskFilter.blur(BlurStyle.normal, 3);
    _drawImage(canvas, paint);

    paint.maskFilter = const MaskFilter.blur(BlurStyle.normal, 5);
    _drawImage(canvas, paint);
  }

  /// 图片滤镜imageFilter
  // 可以通过ImageFilter.blur来让图片模糊，
  // 或通过ImageFilter.matrix进行矩阵变换，测试如下图：
  // ImageFilter.blur(
  //   { double sigmaX = 0.0,
  //     double sigmaY = 0.0
  //   })
  //
  // ImageFilter.matrix(
  //   Float64List matrix4,
  //   { FilterQuality filterQuality = FilterQuality.low })
  void drawImageFilter(Canvas canvas, Size size) {
    canvas.translate(-size.width / 2 + step, -120 - step);
    Paint paint = Paint();

    paint.imageFilter = ui.ImageFilter.blur(sigmaX: 0.4, sigmaY: 0.4);
    _drawImage(canvas, paint);

    paint.imageFilter = ui.ImageFilter.blur(sigmaX: 0.6, sigmaY: 0.6);
    _drawImage(canvas, paint);

    paint.imageFilter = ui.ImageFilter.blur(sigmaX: 1, sigmaY: 1);
    _drawImage(canvas, paint);

    paint.imageFilter = ui.ImageFilter.matrix(Matrix4.skew(pi / 8, 0).storage);
    _drawImage(canvas, paint);
  }

  /// 滤镜质量 filterQuality
  // 滤镜质量一共四种类型: 表现依次如下
  // enum FilterQuality {
  //   none, // 无
  //   low, // 低
  //   medium, //中
  //   high, // 高
  // }
  void drawFilterQuality(Canvas canvas, Size size) {
    canvas.translate(-size.width / 2 + step, -120 - step);
    Paint paint = Paint();

    paint.imageFilter = ui.ImageFilter.blur(sigmaX: 0.6, sigmaY: 0.6);
    paint.maskFilter = const MaskFilter.blur(BlurStyle.inner, 20);
    paint.colorFilter =
        const ColorFilter.mode(Colors.greenAccent, BlendMode.modulate);
    paint.filterQuality = FilterQuality.none;
    _drawImage(canvas, paint);

    paint.filterQuality = FilterQuality.low;
    _drawImage(canvas, paint);

    paint.filterQuality = FilterQuality.medium;
    _drawImage(canvas, paint);

    paint.filterQuality = FilterQuality.high;
    _drawImage(canvas, paint);
  }

  void _drawImage(Canvas canvas, Paint paint) {
    var imgW = image!.width.toDouble();
    var imgH = image!.height.toDouble();
    var src = Rect.fromLTRB(0, 0, imgW, imgH);
    var dst = Rect.fromLTRB(0, 0, imgW / 2, imgH / 2);
    canvas.drawImageRect(image!, src, dst, paint);
    canvas.translate(120 + step, 0);
  }

  @override
  bool shouldRepaint(covariant PaperPainter oldDelegate) => false;
}
